package com.joinway.framework.admin.core.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.joinway.framework.admin.bean.domain.PushLog;
import com.joinway.framework.admin.core.bean.MessagePushResult;
import com.joinway.framework.admin.core.bean.PageMetaData;
import com.joinway.framework.admin.core.bean.PushKey;
import com.joinway.framework.admin.core.service.file.FileConstants;
import com.joinway.framework.admin.core.service.file.FileManager;
import com.joinway.framework.admin.core.service.file.IFileRepository;
import com.joinway.framework.admin.core.type.Platform;
import com.joinway.framework.admin.core.utils.JPushServiceFactory;
import com.joinway.framework.bean.domain.constant.DomainConstants;
import com.joinway.framework.bean.logging.annotation.InputLog;
import com.joinway.framework.bean.logging.annotation.LogIgnore;
import com.joinway.framework.bean.type.Server;
import com.joinway.framework.core.repository.SystemConfigRepository;
import com.joinway.framework.core.utils.AppEnv;
import com.joinway.framework.data.jdbc.repository.TableRepository;
import com.joinway.framework.jpush.bean.JPushResponse;
import com.joinway.framework.jpush.constant.PushConstants;
import com.joinway.framework.jpush.service.JPushService;
import com.joinway.framework.support.logging.LoggingService;

@Service
public class MessagePushService {

	private final static Logger log = LoggerFactory.getLogger(MessagePushService.class);
	
	@Autowired protected SystemConfigRepository systemRepository;
	
	@Autowired protected TableRepository repository;
	
	@Autowired protected LoggingService loggingService;
	
	@Autowired protected IFileRepository<String> fileRepository;
	
	@InputLog
	public MessagePushResult broadcast(String title, @LogIgnore String text, @LogIgnore String html, String sendBy, int port) throws Exception {
		boolean production = systemRepository.getBoolValue(SystemConfigRepository.PushIosProduction);
		int liveDays = systemRepository.getIntValue(SystemConfigRepository.PushLiveDays);

		PageMetaData data = createPage(html, sendBy, port);
		
		Map<String, String> extras = buildExtras(data.getUrl());
		
		JPushService androidService = JPushServiceFactory.getInstance(Platform.Android);
		JPushResponse androidResponse = new JPushResponse();
		if(androidService != null){
			androidResponse = androidService.broadcastMessage(title, extras, liveDays, false);
		}
		log.debug("android result {}", androidResponse);
		
		JPushService iosService = JPushServiceFactory.getInstance(Platform.Ios);
		JPushResponse iosResponse = new JPushResponse();
		if(iosService != null){
			iosResponse = iosService.broadcastMessage(title, extras, liveDays, production);
		}
		log.debug("ios result {}", iosResponse);
		
		String pushStatus = checkPushStatus(androidResponse, iosResponse);
		
		PushLog pushLog = savePushLog(data, title, text, sendBy, DomainConstants.PushTarget.Broadcast, pushStatus, androidResponse, iosResponse);
		
		MessagePushResult result = new MessagePushResult();
		result.setId(pushLog.getId());
		result.setAndroidResponse(androidResponse);
		result.setIosResponse(iosResponse);
		
		return result;
	}
	
	@InputLog
	public MessagePushResult massBroadcast(String title, @LogIgnore String text, @LogIgnore String html, String sendBy, List<PushKey> keys, int port) throws Exception {
		boolean production = systemRepository.getBoolValue(SystemConfigRepository.PushIosProduction);
		int liveDays = systemRepository.getIntValue(SystemConfigRepository.PushLiveDays);

		PageMetaData data = createPage(html, sendBy, port);
		
		Map<String, String> extras = buildExtras(data.getUrl());
		
		JPushService androidService = JPushServiceFactory.getInstance(Platform.Android);
		JPushResponse androidResponse = new JPushResponse();
		if(androidService != null){
			androidResponse = androidService.massMessage(title, extras, getAliases(androidService, keys), liveDays, production);
		}
		log.debug("android result {}", androidResponse);
		
		JPushService iosService = JPushServiceFactory.getInstance(Platform.Ios);
		JPushResponse iosResponse = new JPushResponse();
		if(iosService != null){
			iosResponse = iosService.massMessage(title, extras, getAliases(iosService, keys), liveDays, production);
		}
		log.debug("ios result {}", iosResponse);
		
		String pushStatus = checkPushStatus(androidResponse, iosResponse);
		
		PushLog pushLog = savePushLog(data, title, text, sendBy, DomainConstants.PushTarget.Mass, pushStatus, androidResponse, iosResponse);
		
//		for(PushKey key : keys){
//			UserNoticeLog noticeLog = new UserNoticeLog();
//			noticeLog.setPageId(data.getPageId());
//			noticeLog.setUserId(key.getTargetUserId());
//			noticeLog.setStatus(DomainConstants.NO);
//
//			loggingService.log(noticeLog);
//		}
		
		MessagePushResult result = new MessagePushResult();
		result.setId(pushLog.getId());
		result.setAndroidResponse(androidResponse);
		result.setIosResponse(iosResponse);
		
		return result;
	}
	
	@InputLog
	public MessagePushResult resendMassBroadcast(String sendBy, List<PushKey> keys, int pageId) throws Exception {
		boolean production = systemRepository.getBoolValue(SystemConfigRepository.PushIosProduction);
		int liveDays = systemRepository.getIntValue(SystemConfigRepository.PushLiveDays);
		
		String sql = "select * from push_log where page_id = ?";
		List<PushLog> records = repository.find(PushLog.class, sql, pageId);
		
		PushLog pushLog = CollectionUtils.isNotEmpty(records) ? records.get(0) : null;
		
		if(pushLog == null){
			log.warn("no page id {} was found", pageId);
			return null;
		}
		
		Map<String, String> extras = buildExtras(pushLog.getUrl());
		
		JPushService androidService = JPushServiceFactory.getInstance(Platform.Android);
		JPushResponse androidResponse = new JPushResponse();
		if(androidService != null){
			androidService.massMessage(pushLog.getTitle(), extras, getAliases(androidService, keys), liveDays, production);
		}
		
		JPushService iosService = JPushServiceFactory.getInstance(Platform.Ios);
		JPushResponse iosResponse = new JPushResponse();
		if(iosService != null){
			iosService.massMessage(pushLog.getTitle(), extras, getAliases(iosService, keys), liveDays, production);
		}
		
//		sql = "update user_notice_log set status = :status, accept_time = :acceptTime where user_id = :userId and page_id = :pageId";
//		for(PushKey key : keys){
//			Map<String, Object> params = new HashMap<>();
//			params.put("status", DomainConstants.NO);
//			params.put("acceptTime", null);
//			params.put("userId", key.getTargetUserId());
//			params.put("pageId", pageId);
//			repository.update(params, sql);
//		}
		
		MessagePushResult result = new MessagePushResult();
		result.setAndroidResponse(androidResponse);
		result.setIosResponse(iosResponse);
		
		return result;
	}
	
	protected List<String> getAliases(JPushService service, List<PushKey> keys){
		List<String> aliases = new ArrayList<>();
		
		if(CollectionUtils.isNotEmpty(keys)){
			for(PushKey key : keys){
				if(service != null){
					if(service.getSupportMobileType().equals(key.getMobileType()) || StringUtils.isBlank(key.getMobileType())){
						// if no phone type was specified, send message to all potential platform
						aliases.add(String.valueOf(key.getTargetUserId()));
					}
				}
			}
		}
		
		return aliases;
	}
	
	protected Map<String, String> buildExtras(String url){
		Map<String, String> extras = new HashMap<>();
		extras.put(PushConstants.Message.Url, url);
		extras.put(PushConstants.Message.Time, DateFormatUtils.format(Calendar.getInstance(), "yyyy-MM-dd HH:mm:ss"));
		
		return extras;
	}

	public PageMetaData createPage(String html, String createBy, int port) throws Exception {
		PageMetaData data = new PageMetaData();
		
//		Page page = new Page();
//		page.setText(html);
//		page.setCreateBy(createBy);
//		repository.save(page);
//		
//		int pageId = page.getId();
		
		String fileName = FileManager.getAvailableName() + ".html";

//		NoticePageRepository noticePageRepository = new NoticePageRepository(page.getText());
		String url = FileManager.save(AppEnv.getAppId() + "/" + FileConstants.NoticeFile.Path, fileName, Server.Web, port, fileRepository, html);
		
//		data.setPageId(pageId);
		data.setUrl(url);
		
		return data;
	}
	
//	@Deprecated
//	Map<String, String> buildExtras(String url, String targetUserId){
//		Map<String, String> extras = buildExtras(url);
//		
//		extras.put(PushConstants.Message.UserId, targetUserId);
//		
//		return extras;
//	}
	
	protected PushLog savePushLog(PageMetaData data, String title, String text, String sendBy, String target, String pushStatus, JPushResponse androidResponse, JPushResponse iosResponse) throws Exception {
		PushLog pushLog = new PushLog();
		pushLog.setTitle(title);
		pushLog.setText(text);
		pushLog.setUrl(data.getUrl());
		pushLog.setTarget(target);
		pushLog.setSendBy(sendBy);
		pushLog.setSendTime(new Date());
		pushLog.setPushStatus(pushStatus);
		pushLog.setAndroidMessageId(String.valueOf(androidResponse.getMessageId()));
		pushLog.setAndroidSequenceNo(String.valueOf(androidResponse.getSequenceNo()));
		pushLog.setIosMessageId(String.valueOf(iosResponse.getMessageId()));
		pushLog.setIosSequenceNo(String.valueOf(iosResponse.getSequenceNo()));

		loggingService.log(pushLog);
		
		return pushLog;
	}
	
	protected String checkPushStatus(JPushResponse androidResponse, JPushResponse iosResponse){
//		String pushStatus = AppxDBConstants.PushStatus.Success;
//	
//		do{
//			if(androidResponse == null && iosResponse == null){
//				pushStatus = AppxDBConstants.PushStatus.Fail;
//				break;
//			}
//			
//			if(androidResponse == null || iosResponse == null){
//				pushStatus = AppxDBConstants.PushStatus.Partial;
//				break;
//			}
//			
//			if(androidResponse.getCode() != PushConstants.StatusCode.Success && iosResponse.getCode() != PushConstants.StatusCode.Success){
//				pushStatus = AppxDBConstants.PushStatus.Fail;
//				break;
//			}
//			
//			if(androidResponse.getCode() == PushConstants.StatusCode.Success || iosResponse.getCode() == PushConstants.StatusCode.Success){
//				pushStatus = AppxDBConstants.PushStatus.Partial;
//				break;
//			}
//		}while(false);
//		
//		return pushStatus;
		
		return androidResponse.isSuccess() && iosResponse.isSuccess() ? DomainConstants.PushStatus.Success : DomainConstants.PushStatus.Fail;
	}
	
	protected  static class PushContext{
		String fileName;
		String url;
	}

}




